﻿#region Header

//************************************************************************************************************************
//* Name: Solution wise settings file access
//* Description: This is a basesettings  class which will create Singleton classes is responsible to serve 
//*              All App/Web settings details required while deployment In the constructor, App/Web settings.xml 
//*              file will be read, each tag in the settings.xml file will have a corresponding
//*              property setter & getter here. Through reflection the value in each tag is read and assigned to 
//*              the property setter. Also Cache dependency is set to the XML file itself so 
//*              that whenever app/web settings.xml files are updated the cache gets invalidated
//*              and the singleton instances also gets recreated to refelect the changes in the settings.
//* Created On: 02-Aug-2011
//* Created By: Swathi 
//* Last Modified On: 
//* Last Modified By:
//* Last Modified Reason:
//************************************************************************************************************************

#endregion Header

using System;
using System.Collections.Specialized;
using System.Xml.Linq;
using System.Web;
using System.Web.Caching;
using System.Globalization;
using System.Reflection;

namespace Base.Utils
{
    public abstract class BaseSettings<T>
        where T : class
    {

        private static T _singletonInstance;

        /// <summary>
        /// Initializes a new instance
        /// </summary>
        protected BaseSettings()
        {
            Load();
        }

        /// <summary>
        /// A static instance property 
        /// </summary>
        public static T Instance
        {
            get
            {
                var settingsType = typeof(T);
                var calledFrom = settingsType.Name;
                var cacheKey = calledFrom + "Singleton";
                if (_singletonInstance == null || HttpRuntime.Cache.Get(cacheKey) == null)
                {
                    // the invoke member will create the instance for the type T
                    _singletonInstance = (T)settingsType.InvokeMember(settingsType.Name, BindingFlags.CreateInstance, null, null, null, CultureInfo.InvariantCulture);
                    HttpRuntime.Cache.Insert(cacheKey, _singletonInstance,
                                             new CacheDependency(
                                                 HttpContext.Current.Server.MapPath("~/App_Data/" + calledFrom + ".xml")));
                }
                _singletonInstance = HttpRuntime.Cache.Get(cacheKey) as T;
                return _singletonInstance;
            }
        }


        /// <summary>
        /// To load the xml files data 
        /// </summary>
        public void Load()
        {
            var settingsType = GetType();
            var calledFrom = settingsType.Name;

            //------------------------------------------------------------
            // Enumerate through individual settings nodes
            //------------------------------------------------------------
            var dic =
                GetWebSettingsFromXml(HttpContext.Current.Server.MapPath("~/App_Data/" + calledFrom + ".xml"), calledFrom);

            foreach (string key in dic.Keys)
            {
                //------------------------------------------------------------
                // Extract the setting's name/value pair
                //------------------------------------------------------------
                var name = key;
                var value = dic[key];

                //------------------------------------------------------------
                // Enumerate through public properties of this instance
                //------------------------------------------------------------
                for (var index = 0; index < settingsType.GetProperties().Length; index++)
                {
                    var propertyInformation = settingsType.GetProperties()[index];
                    if (!propertyInformation.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) continue;
                    //------------------------------------------------------------
                    // Attempt to apply configured setting
                    //------------------------------------------------------------
                    if (propertyInformation.CanWrite)
                    {
                        propertyInformation.SetValue(this,
                                                     Convert.ChangeType(value, propertyInformation.PropertyType,
                                                                        CultureInfo.CurrentCulture), null);
                    }

                    break;
                }
            }

        }

        /// <summary>
        /// To read the xml file data to return the string dictionary
        /// </summary>
        /// <param name="pFilePath"></param>
        /// <param name="pExpression"></param>
        /// <returns></returns>
        private static StringDictionary GetWebSettingsFromXml(string pFilePath, string pExpression)
        {
            var dic = new StringDictionary();
            XElement doc;
            if (HttpRuntime.Cache.Get(pFilePath) == null)
            {
                doc = XElement.Load(pFilePath);
                HttpRuntime.Cache.Insert(pFilePath, doc, new CacheDependency(pFilePath));
            }
            else
            {
                doc = HttpRuntime.Cache.Get(pFilePath) as XElement;
            }

            if (doc != null)
            {
                foreach (XElement seetingsNode in doc.Elements())
                {
                    var name = seetingsNode.Name.ToString();
                    var value = seetingsNode.Value;
                    if (dic.ContainsKey(name))
                        continue;
                    dic.Add(name, value);
                }
            }
            return dic;
        }
    }
}
